﻿/***********************************************************************
 * <copyright file="Extensions.cs" company="BUCA JSC">
 * -->    Copyright (C) statement. All right reserved
 * </copyright>
 * 
 * Created:   Tuanhm
 * Email:    Tuanhm@humg@gmail.com
 * Website:
 * Create Date: Thursday, March 27, 2014
 * Usage: 
 * 
 * RevisionHistory: 
 * Date         Author               Description 
 * 
 * ************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;

// ReSharper disable once CheckNamespace
namespace DataObjects.Shared
{
    /// <summary>
    /// Useful set of Extension methods for Data Access purposes.
    /// </summary>
    public static class Extensions
    {
        /// <summary>
        /// Transform object into Identity data type (integer).
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultId">Optional default value is -1.</param>
        /// <returns>Identity value.</returns>
        public static int AsId(this object item, int defaultId = -1)
        {
            if (item == null)
                return defaultId;

            int result;
            return !int.TryParse(item.ToString(), out result) ? defaultId : result;
        }

        /// <summary>
        /// Transform object into integer data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultInt">Optional default value is default(int).</param>
        /// <returns>The integer value.</returns>
        public static int AsInt(this object item, int defaultInt = default(int))
        {
            if (item == null)
                return defaultInt;

            int result;
            return !int.TryParse(item.ToString(), out result) ? defaultInt : result;
        }

        /// <summary>
        /// Ases the integer.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="defaultInt">The default int.</param>
        /// <returns></returns>
        public static int? AsInteger(this object item, int defaultInt = default(int))
        {
            if (item == null)
                return null;

            int result;
            return !int.TryParse(item.ToString(), out result) ? defaultInt : result;
        }
        /// <summary>
        /// Transform object into short data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultShort">Optional default value is default(short).</param>
        /// <returns>The integer value.</returns>
        public static short AsShort(this object item, short defaultShort = default(short))
        {
            if (item == null)
                return defaultShort;

            short result;
            return !short.TryParse(item.ToString(), out result) ? defaultShort : result;
        }

        /// <summary>
        /// Transform object into long data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultlong">Optional default value is default(long).</param>
        /// <returns>The long value.</returns>
        public static long? AsLongIsNull(this object item, long defaultlong = default(long))
        {
            if (item == null)
                return null;

            long result;
            return !long.TryParse(item.ToString(), out result) ? defaultlong : result;
        }
        /// <summary>
        /// Transform object into long data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultlong">Optional default value is default(long).</param>
        /// <returns>The long value.</returns>
        public static long AsLong(this object item, long defaultlong = default(long))
        {
            if (item == null)
                return defaultlong;

            long result;
            return !long.TryParse(item.ToString(), out result) ? defaultlong : result;
        }
        /// <summary>
        /// Ases the float.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="defaultFloat">The default float.</param>
        /// <returns></returns>
        public static float AsFloat(this object item, float defaultFloat = default(float))
        {
            if (item == null)
                return defaultFloat;

            float result;
            return !float.TryParse(item.ToString(), out result) ? defaultFloat : result;
        }
        /// <summary>
        /// Transform object into double data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultDouble">Optional default value is default(double).</param>
        /// <returns>The double value.</returns>
        public static double AsDouble(this object item, double defaultDouble = default(double))
        {
            if (item == null)
                return defaultDouble;

            double result;
            return !double.TryParse(item.ToString(), out result) ? defaultDouble : result;
        }
        /// <summary>
        /// Ases the int for null.
        /// </summary>
        /// <param name="item">The item.</param>
        /// <param name="defaultInt">The default int.</param>
        /// <returns></returns>
        public static int? AsIntForNull(this object item, int? defaultInt = null)
        {
            if (item == null)
                return defaultInt;

            int result;
            if (!int.TryParse(item.ToString(), out result))
                return defaultInt;

            return result;
        }
        /// <summary>
        /// Transform object into decimal data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultDecimal">Optional default value is default(decimal).</param>
        /// <returns>The double value.</returns>
        public static decimal AsDecimal(this object item, decimal defaultDecimal = default(decimal))
        {
            if (item == null)
                return defaultDecimal;

            decimal result;
            return !decimal.TryParse(item.ToString(), out result) ? defaultDecimal : result;
        }

        /// <summary>
        /// Transform object into string data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultString">Optional default value is default(string).</param>
        /// <returns>The string value.</returns>
        public static string AsString(this object item, string defaultString = default(string))
        {
            if (item == null || item.Equals(DBNull.Value))
                return defaultString;

            return item.ToString().Trim();
        }

        /// <summary>
        /// Transform object into DateTime data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultDateTime">Optional default value is default(DateTime).</param>
        /// <returns>The DateTime value.</returns>
        public static DateTime AsDateTime(this object item, DateTime defaultDateTime = default(DateTime))
        {
            if (item == null || string.IsNullOrEmpty(item.ToString()))
                return defaultDateTime;

            DateTime result;
            return !DateTime.TryParse(item.ToString(), out result) ? defaultDateTime : result;
        }

        /// <summary>
        /// Transform object into bool data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <param name="defaultBool">Optional default value is default(bool).</param>
        /// <returns>The bool value.</returns>
        public static bool AsBool(this object item, bool defaultBool = default(bool))
        {
            return item == null ? defaultBool : new List<string> { "yes", "y", "true" }.Contains(item.ToString().ToLower());
        }

        /// <summary>
        /// Transform string into byte array.
        /// </summary>
        /// <param name="s">The object to be transformed.</param>
        /// <returns>The transformed byte array.</returns>
        public static byte[] AsByteArray(this string s)
        {
            return string.IsNullOrEmpty(s) ? null : Convert.FromBase64String(s);
        }

        /// <summary>
        /// Transform object into base64 string.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <returns>The base64 string value.</returns>
        public static string AsBase64String(this object item)
        {
            return item == null ? null : Convert.ToBase64String((byte[])item);
        }

        /// <summary>
        /// Transform Binary into base64 string data type. 
        /// Note: This is used in LINQ to SQL only.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <returns>The base64 string value.</returns>
        public static string AsBase64String(this Binary item)
        {
            return item == null ? null : Convert.ToBase64String(item.ToArray());
        }

        /// <summary>
        /// Transform base64 string to Binary data type. 
        /// Note: This is used in LINQ to SQL only.
        /// </summary>
        /// <param name="s">The base 64 string to be transformed.</param>
        /// <returns>The Binary value.</returns>
        public static Binary AsBinary(this string s)
        {
            return string.IsNullOrEmpty(s) ? null : new Binary(Convert.FromBase64String(s));
        }

        /// <summary>
        /// Transform object into Guid data type.
        /// </summary>
        /// <param name="item">The object to be transformed.</param>
        /// <returns>The Guid value.</returns>
        public static Guid AsGuid(this object item)
        {
            try { return new Guid(item.ToString()); }
            catch { return Guid.Empty; }
        }

        /// <summary>
        /// Concatenates SQL and ORDER BY clauses into a single string. 
        /// </summary>
        /// <param name="sql">The SQL string</param>
        /// <param name="sortExpression">The Sort Expression.</param>
        /// <returns>Contatenated SQL Statement.</returns>
        public static string OrderBy(this string sql, string sortExpression)
        {
            if (string.IsNullOrEmpty(sortExpression))
                return sql;

            return sql + " ORDER BY " + sortExpression;
        }

        /// <summary>
        /// Takes an enumerable source and returns a comma separate string.
        /// Handy to build SQL Statements (for example with IN () statements) from object collections.
        /// </summary>
        /// <typeparam name="T">The Enumerable type</typeparam>
        /// <typeparam name="TU">The original data type (typically identities - int).</typeparam>
        /// <param name="source">The enumerable input collection.</param>
        /// <param name="func">The function that extracts property value in object.</param>
        /// <returns>The comma separated string.</returns>
        public static string CommaSeparate<T, TU>(this IEnumerable<T> source, Func<T, TU> func)
        {
            return string.Join(",", source.Select(s => func(s).ToString()).ToArray());
        }
    }
}
